/*
 *******************************************************************************
 *
 * Copyright (C) 2019-2020 Dialog Semiconductor.
 * This computer program includes Confidential, Proprietary Information
 * of Dialog Semiconductor. All Rights Reserved.
 *
 *******************************************************************************
 */

package com.example.suota.suota.suota;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.os.Build;
import android.util.Log;

import androidx.annotation.NonNull;

import com.example.suota.suota.global.SuotaLibLog;
import com.example.suota.suota.utils.SuotaUtil;


class GattOperation {

    enum OperationType {
        READ,
        WRITE,
        WRITE_DESCRIPTOR,
        MTU_REQUEST,
        REBOOT_COMMAND
    }

    private static final String TAG = "GattOperation";

    private BluetoothGattCharacteristic characteristic;
    private BluetoothGattDescriptor descriptor;
    private final OperationType type;
    private byte[] value;
    private int mtu;

    GattOperation(int mtu) {
        this.type = OperationType.MTU_REQUEST;
        this.mtu = mtu;
    }

    GattOperation(@NonNull BluetoothGattCharacteristic characteristic) {
        this.type = OperationType.READ;
        this.characteristic = characteristic;
    }

    GattOperation(OperationType type, @NonNull BluetoothGattCharacteristic characteristic, int value) {
        this.type = type;
        this.characteristic = characteristic;
        this.value = new byte[] { (byte) value, (byte) (value >>> 8), (byte) (value >>> 16), (byte) (value >>> 24) };
    }

    GattOperation(@NonNull BluetoothGattCharacteristic characteristic, short value) {
        this.type = OperationType.WRITE;
        this.characteristic = characteristic;
        this.value = new byte[] { (byte) value, (byte) (value >>> 8) };
    }

    GattOperation(@NonNull BluetoothGattCharacteristic characteristic, byte[] value) {
        this.type = OperationType.WRITE;
        this.characteristic = characteristic;
        this.value = value;
    }

    GattOperation(@NonNull BluetoothGattDescriptor descriptor, byte[] value) {
        this.type = OperationType.WRITE_DESCRIPTOR;
        this.descriptor = descriptor;
        this.value = value;
    }

    byte[] getValue() {
        return value;
    }

    BluetoothGattCharacteristic getCharacteristic() {
        return characteristic;
    }

    private BluetoothGattDescriptor getDescriptor() {
        return descriptor;
    }

    public OperationType getType() {
        return type;
    }

    boolean execute(@NonNull BluetoothGatt gatt) {
        if (type == OperationType.WRITE || type == OperationType.REBOOT_COMMAND) {
            return executeWriteCharacteristic(gatt);
        } else if (type == OperationType.READ) {
            return executeReadCharacteristic(gatt);
        } else if (type == OperationType.WRITE_DESCRIPTOR) {
            return executeWriteDescriptor(gatt);
        } else if (type == OperationType.MTU_REQUEST) {
            return executeMtuRequest(gatt);
        }
        return false;
    }

    @SuppressLint("MissingPermission")
    protected boolean executeWriteCharacteristic(@NonNull BluetoothGatt gatt) {
        if (SuotaLibLog.GATT_OPERATION)
            Log.d(TAG, "Write characteristic: " + characteristic.getUuid() + " " + SuotaUtil.hexArray(value));
        characteristic.setValue(getValue());
        return gatt.writeCharacteristic(characteristic);
    }

    @SuppressLint("MissingPermission")
    protected boolean executeReadCharacteristic(@NonNull BluetoothGatt gatt) {
        if (SuotaLibLog.GATT_OPERATION)
            Log.d(TAG, "Read characteristic: " + characteristic.getUuid());
        return gatt.readCharacteristic(characteristic);
    }

    @SuppressLint("MissingPermission")
    protected boolean executeWriteDescriptor(@NonNull BluetoothGatt gatt) {
        if (SuotaLibLog.GATT_OPERATION)
            Log.d(TAG, "Write descriptor: " + descriptor.getCharacteristic().getUuid() + " " + descriptor.getUuid() + " " + SuotaUtil.hexArray(value));
        descriptor.setValue(getValue());
        return gatt.writeDescriptor(descriptor);
    }

    @SuppressLint("MissingPermission")
    protected boolean executeMtuRequest(@NonNull BluetoothGatt gatt) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
            return false;
        if (SuotaLibLog.GATT_OPERATION)
            Log.d(TAG, "MTU request: " + mtu);
        return gatt.requestMtu(mtu);
    }
}
